import os
import random
import sys,math

import time

from pyglet.gl import *
import pyglet
from pyglet.window import key

import iceberg

from OpenSteer.pyopensteer2D import SimpleVehicule,LocalSpace,Vector2D

def center_anchor(img):
    img.anchor_x=img.width//2
    img.anchor_y=img.height//2


def angle_vector(v):
    Pi = 3.141592
    x,y=v
    if x == 0 :
        if y>=0 :
            angle = Pi *0.5
        else : 
            angle = -Pi * 0.5
    else :
        angle = math.atan(y / x)
        if x<0:
            angle+=Pi
    
        
    if angle < 0 :
        angle += 2 * Pi
    
    return angle    



def angle_from_vector(v):
    return angle_vector(v)/3.141592*180.0

def renderLightAlpha(center,radius,intensity,depth):
    assert (intensity > 0. and intensity <= 1.)

    numSubdivisions = 32
    x,y=center
    gl.glBegin(gl.GL_TRIANGLE_FAN)
    
    gl.glColor4f(1., 1., 1.,  intensity)
    gl.glVertex3f(x, y, depth)
      
    # Set edge colour for rest of shape
    gl.glColor4f(0.,0.,0.,0.)
    
    angle=0
    for i in range(numSubdivisions):
        angle+=(3.141592*2)/numSubdivisions
        gl.glVertex3f( radius*math.cos(angle) +x,radius*math.sin(angle) + y, depth);  
    
      
    gl.glVertex3f(x+radius, y, depth)
    
    gl.glEnd()


    
class PulsingSprite(pyglet.sprite.Sprite):
    own_image=pyglet.resource.image('red_light.png')
    width = own_image.width
    height = own_image.height
    center_anchor(own_image)
    
    def __init__(self, x, y,batch):
    
        self.pos=(x,y)
        super(PulsingSprite, self).__init__(self.own_image, x, y, batch=batch)
        self.nodeMaxScale = 1.2
        self.nodeScale=self.nodeMinScale =0.8
        
        self.frequency=2.0
        self.nodeScaleStep = (self.nodeMaxScale-self.nodeMinScale)*self.frequency
        

    def update(self,dt):
        self.nodeScale +=  self.nodeScaleStep* dt
        if (self.nodeScale >= self.nodeMaxScale) or (self.nodeScale <= self.nodeMinScale):
                self.nodeScaleStep = -self.nodeScaleStep
       
        self.scale= self.nodeScale
       
        
class GLSprite():
    def __init__(self,gw,name,pos,target_loc):
        
        self.parent=gw
        self.position=pos
        self.name=name
        self.scale=5.0
        
        if target_loc :
            self.target = target_loc
            
        self.sv=SimpleVehicule(True)
        self.sv.setMaxSpeed(100.0)
        self.sv.setMaxForce(100.0)
        self.sv.radius=self.scale*2
        self.sv.setMass(0.2)
        
        self.sv.setPosition(self.position)
        self.targetSp=PulsingSprite(self.target[0],self.target[1],self.parent.target_Batch)
        
        self.vertex_list=pyglet.graphics.vertex_list(3,\
                ("v2i",(-1,-1,0,2,1,-1)),\
                ("c3B",(0,0,255,255,0,128,0,0,255)))
        
        
        self.angle=angle_from_vector(self.sv.forward)
    
    def hit(self,scr_pos):
        (x,y)=[a-b for a,b in zip(scr_pos,self.position)]
        dist=math.hypot(x,y)
        print dist
        if dist<=self.sv.radius : 
            return True
        return False
    
    
        
    def on_draw(self):
        glPushMatrix()
        
        x,y=self.position
        pyglet.gl.glTranslatef(x,y,0.0)
        pyglet.gl.glScalef(self.scale,self.scale,1.0)
        pyglet.gl.glRotatef(self.angle,0.0,0.0,1.0)
        self.vertex_list.draw(GL_TRIANGLES)
        glPopMatrix()
        
    def update(self,dt):
        
        force=Vector2D((0.0,0.0))
        if self.target:
            force=self.sv.steerForSeek(self.target)
        
        self.sv.applySteeringForce(force,dt)
        self.position = self.sv.position
        self.angle=-angle_from_vector(self.sv.forward)
        self.targetSp.update(dt)
             

class Actuator(object):
    def __init__(self,start, end,duration):
        self.X=start
        self.Y=end
        self.startT=time.clock()
        self.endTime=self.startT+duration
        self.duration=duration
    
    def val(self):
        t=time.clock()
        if t>=self.endTime:
            return (True,self.Y)
        
        return (False,[self.func(a,b) for a,b in zip(self.X,self.Y)])
    
    def func(self,a,b):
        t=time.clock()
        t=(t-self.startT)/self.duration
        
        return a+(b-a)*t
    
class SineActuator(Actuator):
    
    def __init__(self,start, end,duration):
        super(SineActuator,self).__init__(start, end,duration)
        
    
    
    def func(self,a,b):
        t=time.clock()
        t=(t-self.startT)/self.duration
        angle=3.141592*0.5*(2*t-1)
        return (1+math.sin(angle))*0.5*(b-a)+a
    
class SqrActuator(Actuator):
    
    def __init__(self,start, end,duration):
        super(SqrActuator,self).__init__(start, end,duration)
        
    
    
    def func(self,a,b):
        t=time.clock()
        t=(t-self.startT)/self.duration
        t=t**3
        return a+(b-a)*t

class GameWindow(pyglet.window.Window):
    def __init__(self,width,height):
        super(GameWindow,self).__init__(width,height)
        gl.glDepthMask(True)
        gl.glClearDepth(1.0)
        gl.glClearColor(0.0, 0.0, 0.0, 0.0);
        gl.glClear(gl.GL_COLOR_BUFFER_BIT |gl.GL_DEPTH_BUFFER_BIT | gl.GL_STENCIL_BUFFER_BIT)
  
        self.center=(width//2,height//2)
        self.window_size=(width,height)
        
        self.offset=(0.0,0.0)
        
        self.camera_sv=SimpleVehicule(True)
        
        self.camera_sv.setMaxSpeed(1000.0)
        self.camera_sv.setMaxForce(1000.0)
        self.camera_sv.radius=1.0
        self.camera_sv.setMass(0.02)
        
        self.camera_sv.setPosition((0.0,0.0))
        
        self.zoom=1.0
        
        self.selected=None
        
        self.sprite_id=0
        self.SSs_batch = pyglet.graphics.Batch()
        self.sprites = {}
        self.SV=[]
        self.target_Batch= pyglet.graphics.Batch()
        self.label = pyglet.text.Label('Press space to add a ball, backspace to remove',
                                  font_size=14,
                                  x=0, y=00, 
                                  anchor_x='center')

        pyglet.clock.schedule_interval(self.update, 1/30.)
        
        self.camera_actuator=None
        self.ic=None
    
    def on_key_press(self,symbol, modifiers):
        if symbol == key.SPACE:
            #SSs.append(SteeringSprite())
            name="sprite#%i"%(self.sprite_id)
            self.sprite_id+=1
            self.sprites[name]=GLSprite(self,name,((0.5-random.random()) * (self.width ),(0.5-random.random()) * (self.height)),((0.5-random.random()) * (self.width ),(0.5-random.random()) * (self.height)))
            self.SV.append(self.sprites[name].sv)
            self.selected=self.sprites[name]

        elif symbol == key.A:
            name="iceberg#%i"%(self.sprite_id)
            self.sprite_id+=1
            self.ic=iceberg.Iceberg(name,((10,10),(10,100),(100,100),(100,10)))
            

        elif symbol == key.BACKSPACE:
            if self.sprites:
                del self.sprites[-1]
                del self.SSs[-1]
                
        elif symbol == key.ESCAPE:
            pyglet.app.exit()

    def on_mouse_release(self,x, y, button, modifiers):
        print "(%i,%i)"%(x,y)
        print self.screen_to_space((x,y))
        if button==pyglet.window.mouse.MIDDLE:
            print "camera pos :"+str( self.camera_sv.position)
            self.camera_actuator=SqrActuator(self.camera_sv.position,self.screen_to_space((x,y)),1.)
            
            
            return True
        
        self.find_selected(self.screen_to_space((x,y)))
        


    def on_mouse_scroll(self,x, y, scroll_x, scroll_y):
        step=math.fabs(scroll_y)
        
        if scroll_y>0 :
            fact=1.05
        else :
            fact=0.95
            
        for i in range(step):
            self.zoom*=fact

    def on_draw(self):
        
        if self.camera_actuator:
            end,pos=self.camera_actuator.val()
            if end:
                self.camera_actuator=None
            self.camera_sv.setPosition(pos)
         
        
        
        
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()
        
        glTranslatef(self.center[0],self.center[1],0.0)
        
        sc=self.space_to_screen(self.camera_sv.position)
        
        glScalef(self.zoom,self.zoom,1.0)
        
        glTranslatef(-self.camera_sv.position[0],-self.camera_sv.position[1],0.0)
        
        #glEnable(gl.GL_ALPHA_TEST)
        
        #glAlphaFunc(gl.GL_EQUAL, 1.0)
       
        #window.clear()
        for gls in self.sprites.values():
            gls.on_draw()
            
        #SSs_batch.draw()
        self.target_Batch.draw()
        self.label.draw()
        
        if self.ic:
            self.ic.draw((10.0,0.0,0.0,))

    def screen_to_space(self,sc_pos):
        sp=[(a-b)/self.zoom for a,b in zip(sc_pos,self.center)]
        #sp[1]=-sp[1]
        sp=[a+b for a,b in zip(sp,self.camera_sv.position)]
        
        
        
        return sp
    
    def space_to_screen(self, sp_pos):
          
        sc=[(a-b)*self.zoom for a,b in zip(sp_pos,self.camera_sv.position)]
        #sc[1]=-sc[1]
        sc=[a+b for a,b in zip(sc,self.center)]
        return sc
    
    
    def update(self,dt):
        for ss in self.sprites.values():
            ss.update(dt)
        
##        if self.selected:
##            force=self.camera_sv.steerForSeek(self.selected.position)
##            self.camera_sv.applySteeringForce(force,dt)

    def find_selected(self,loc):
        #get centered screen coordinates
        #csc=((x-self.center[0])/self.zoom,y-self.center[1]/self.zoom)
        
        
        print "space coord : "+str(loc)
        
        for name in self.sprites:
            s=self.sprites[name]
            print name+" -> "+str(s.position)
            if s.hit(loc) :
                print "sprinte %s hit !"%(name)
                break
            


#gl.glEnable(gl.GL_BLEND)
#glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)




if __name__ == '__main__':
    window=GameWindow(800,600)
    
    #print window.space_to_screen(window.screen_to_space((100,10)))
    
    pyglet.app.run()  
              
